#include "StdAfx.h"
#include "HausdorffSolver.h"
#include "Hausdorff.h"
#include "Mesh.h"
#include "DXUT.h"

const int INITIAL_BUFFER_SIZE = 50000;

CHausdorffSolver::CHausdorffSolver(void)
: m_pVBCube(NULL)
, m_pIBCube(NULL)
{
}


CHausdorffSolver::~CHausdorffSolver(void)
{
}

void CHausdorffSolver::Solve()
{
	//kernelRun();

	assert(m_pMesh[0]);
	assert(m_pMesh[1]);

	// Entire domain space range is minkowski sum of mesh A and B.
	DATA_TYPE vBoundsMinA[3];
	DATA_TYPE vBoundsMaxA[3];
	DATA_TYPE vBoundsMinB[3];
	DATA_TYPE vBoundsMaxB[3];
	m_pMesh[0]->GetBounds(vBoundsMinA, vBoundsMaxA);
	m_pMesh[1]->GetBounds(vBoundsMinB, vBoundsMaxB);
	DATA_TYPE vHalfSizeB[3];
	for (int i = 0; i < 3; ++i)
	{
		vHalfSizeB[i] = (vBoundsMaxB[i] - vBoundsMinB[i]) * 0.5f;
	}

	m_vEntireDomainMin[0] = vBoundsMinA[0] - vHalfSizeB[0];
	m_vEntireDomainMax[0] = vBoundsMaxA[0] + vHalfSizeB[0];
	m_vEntireDomainMin[1] = vBoundsMinA[1] - vHalfSizeB[1];
	m_vEntireDomainMax[1] = vBoundsMaxA[1] + vHalfSizeB[1];
	m_vEntireDomainMin[2] = vBoundsMinA[2] - vHalfSizeB[2];
	m_vEntireDomainMax[2] = vBoundsMaxA[2] + vHalfSizeB[2];

	// Insert initial input
	//m_vTaskBuffer.resize(INITIAL_BUFFER_SIZE);



	// Subdivide the domain range to 8 ranges.

	// Insert ranges to task1 buffer.

	// For each task1,
	//		(GPU) Compute the hausdorff distance minmax interval between (the domain)? and all bounding spheres of A in a specific level.
	//		(CPU) If an interval's max is less than another interval's min, discard the interval.
	//		Insert remaining intervals to task2 buffer.
	//
	//		For each task2,
	//			(GPU) Compute the hausdorff distance minmax interval between all BSs of A in task2 buffer and all BSs of B in a specific level.
	//			(CPU) If an interval's max is less than another interval's min, discard the interval.
	//			Insert remaining intervals to task3 buffer.
	//
	//		From task3 buffer, 
}

void CHausdorffSolver::RenderScene()
{
	RenderDomain();
}

void CHausdorffSolver::RenderDomain()
{
	LPDIRECT3DDEVICE9 pDevice9 = DXUTGetD3D9Device();
	D3DMATERIAL9 mtrl;
	ZeroMemory( &mtrl, sizeof( D3DMATERIAL9 ) );
	mtrl.Emissive = D3DXCOLOR( 1.0f, 1.0f, 1.0f, 1.0f );
	pDevice9->SetMaterial( &mtrl );

	D3DXMATRIX matTranslation, matScaling, matWorld;
	D3DXVECTOR3 vCenter, vScale;
	for (int  i = 0; i < 3; ++i)
	{
		vCenter[i] = (float)(m_vEntireDomainMin[i] + m_vEntireDomainMax[i]) * 0.5f;
		vScale[i] = vCenter[i] - (float)m_vEntireDomainMin[i];
	}

	D3DXMatrixTranslation(&matTranslation, vCenter.x, vCenter.y, vCenter.z);
	D3DXMatrixScaling(&matScaling, vScale.x, vScale.y, vScale.z);

	matWorld = matScaling * matTranslation;
	pDevice9->SetTransform( D3DTS_WORLD, &matWorld );

	pDevice9->SetStreamSource( 0, m_pVBCube, 0, sizeof( CUSTOMVERTEX ) );
	pDevice9->SetIndices( m_pIBCube );
	pDevice9->SetFVF( D3DFVF_CUSTOMVERTEX );
	pDevice9->DrawIndexedPrimitive( D3DPT_LINELIST, 0, 0, 8, 0, 12 );
}

HRESULT CHausdorffSolver::InitD3DBuffer()
{
	LPDIRECT3DDEVICE9 pDevice9 = DXUTGetD3D9Device();

	SAFE_RELEASE( m_pVBCube );
	SAFE_RELEASE( m_pIBCube );

	if( FAILED( pDevice9->CreateVertexBuffer( 8 * sizeof( CUSTOMVERTEX ),
		0, D3DFVF_CUSTOMVERTEX,
		D3DPOOL_DEFAULT, &m_pVBCube, NULL ) ) )
	{
		return E_FAIL;
	}

	// Fill the vertex buffer. We are algorithmically generating a cylinder
	// here, including the normals, which are used for lighting.
	CUSTOMVERTEX* pVertices;
	if( FAILED( m_pVBCube->Lock( 0, 0, ( void** )&pVertices, 0 ) ) )
		return E_FAIL;

	pVertices[0].position = D3DXVECTOR3( -1.f, -1.f, -1.f );
	pVertices[1].position = D3DXVECTOR3(  1.f, -1.f, -1.f );
	pVertices[2].position = D3DXVECTOR3(  1.f,  1.f, -1.f );
	pVertices[3].position = D3DXVECTOR3( -1.f,  1.f, -1.f );
	pVertices[4].position = D3DXVECTOR3( -1.f, -1.f,  1.f );
	pVertices[5].position = D3DXVECTOR3(  1.f, -1.f,  1.f );
	pVertices[6].position = D3DXVECTOR3(  1.f,  1.f,  1.f );
	pVertices[7].position = D3DXVECTOR3( -1.f,  1.f,  1.f );

	m_pVBCube->Unlock();

	if( FAILED( pDevice9->CreateIndexBuffer( 24 * sizeof(DWORD), 0, D3DFMT_INDEX32, D3DPOOL_DEFAULT, &m_pIBCube, NULL ) ) )
	{
		return E_FAIL;
	}

	DWORD* pIndices;
	if( FAILED( m_pIBCube->Lock( 0, 0, ( void** )&pIndices, 0 ) ) )
		return E_FAIL;
	pIndices[0] = 0;
	pIndices[1] = 1;
	pIndices[2] = 1;
	pIndices[3] = 2;
	pIndices[4] = 2;
	pIndices[5] = 3;
	pIndices[6] = 3;
	pIndices[7] = 0;

	pIndices[8] = 4;
	pIndices[9] = 5;
	pIndices[10] = 5;
	pIndices[11] = 6;
	pIndices[12] = 6;
	pIndices[13] = 7;
	pIndices[14] = 7;
	pIndices[15] = 4;

	pIndices[16] = 0;
	pIndices[17] = 4;
	pIndices[18] = 1;
	pIndices[19] = 5;
	pIndices[20] = 2;
	pIndices[21] = 6;
	pIndices[22] = 3;
	pIndices[23] = 7;
	m_pIBCube->Unlock();

	return S_OK;
}

void CHausdorffSolver::OnDestroy()
{
	SAFE_RELEASE(m_pVBCube);
	SAFE_RELEASE(m_pIBCube);
}

void CHausdorffSolver::OnLostDevice()
{
	OnDestroy();
}

void CHausdorffSolver::OnResetDevice()
{
	InitD3DBuffer();
}